#include "robot_cleaner.h"

Position::Position(int x, int y, Direction d) : x(x), y(y), d(d) {}

bool Position::operator==(const Position& p) const {
    return this->x == p.x && this->y == p.y && this->d == p.d;
}

Position Position::forwardStep(int step) {
    Position p = *this;
    switch (p.d) {
        case NORTH:
            p.y += step;
            break;
        case EAST:
            p.x += step;
            break;
        case SOUTH:
            p.y -= step;
            break;
        case WEST:
            p.x -= step;
            break;
    }
    return p;
}

Position Position::backwardStep(int step) { return this->forwardStep(-step); }

class TurnLeftCommand : public Command {
private:
    void execute(Position& position) override {
        position.d = (Direction)((position.d + 3) % 4);
    }
};

class TurnRightCommand : public Command {
private:
    void execute(Position& position) override {
        position.d = (Direction)((position.d + 1) % 4);
    }
};

class ForwardCommand : public Command {
private:
    void execute(Position& position) override {
        position = position.forwardStep(1);
    }
};

class BackwardCommand : public Command {
private:
    void execute(Position& position) override {
        position = position.backwardStep(1);
    }
};

class RoundCommand : public Command {
private:
    void execute(Position& position) override {
        position.d = (Direction)((position.d + 2) % 4);
    }
};

Command* CommandFactory::createCommand(const CommandType type) {
    switch (type) {
        case TURN_LEFT:
            return new TurnLeftCommand();
        case TURN_RIGHT:
            return new TurnRightCommand();
        case FORWARD:
            return new ForwardCommand();
        case BACKWARD:
            return new BackwardCommand();
        case ROUND:
            return new RoundCommand();
        default:
            return nullptr;
    }
}

RobotCleaner::RobotCleaner(int x, int y, Direction d) : position(x, y, d) {}

void RobotCleaner::executeCommand(Command*& command) {
    if (command != nullptr) {
        command->execute(this->position);
        delete command;
        command = nullptr;
    }
}

Position RobotCleaner::getPosition() const { return this->position; }
